package src;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Iterator;



public class CargadorDeArchivo extends Cargador {
	
	//El mapa servira para cargar la misma instancia de la persona
	private AbstractMap<String, Persona> personas;

	
	
	public final static String SEPARADOR_PRINCIPAL = ": ";
	public final static String SEPARADOR_NOMBRES   = ",";
	
	
	
	/*
	 * 
	 * Carga las tablas de preferencias a partir de un archivo; recive la ruta del archivo
	 */

	public CargadorDeArchivo(String archivo){
		super();
		personas= new HashMap<String,Persona>();
		File f = new File(archivo);
		this.preferenciasHombres= new TablaDePreferencias();
		this.preferenciasMujeres= new TablaDePreferencias();
		this.esCoherente=true;
		BufferedReader lectorArchivo;
		try{
		lectorArchivo = new BufferedReader(new FileReader(f));
		}
		catch(FileNotFoundException e ){
			throw new ArchivoNoExiste(archivo);
		}
		
		try {
			parsearArchivo(lectorArchivo);
		} catch (IOException e) {
			throw new ErrorDeLectura(archivo);
		}
	}

	private void parsearArchivo(BufferedReader lectorArchivo)
			throws IOException {
		
		parsearPrimerParte(lectorArchivo);
		//sigo leyendo la segunda parte del archivo con las preferencias del otro genero
		try{
		parsearSegundaParte(lectorArchivo);
		}
		catch(NoExistePersonaConNombreExcepcion e){
			this.esCoherente=false;
		}
		comprobarCoherencia();
		if(!this.esCoherente)
			throw new ArchivoIncoherenteError();
	
	}

	private void parsearSegundaParte(BufferedReader lectorArchivo) throws IOException {
		String linea=null;
		boolean eof=false;
		if(lectorArchivo.ready())
			linea=lectorArchivo.readLine();
		
		while(!eof){
			if(!lectorArchivo.ready())
				eof=true;
			if(!linea.contains(SEPARADOR_PRINCIPAL))
				throw new ErrorDeSintaxis("Se esperaba " + SEPARADOR_PRINCIPAL + " en esta linea");
			// separo la primer parte desde el separador principal, que es el nombre de la persona de sus preferencias
			String nombrePersona= linea.split(SEPARADOR_PRINCIPAL)[0],
					preferencias=linea.split(SEPARADOR_PRINCIPAL)[1];
			String[] nombresPreferencias = preferencias.split(SEPARADOR_NOMBRES);
			
			Persona persona;
			if(!this.personas.containsKey(nombrePersona))
				persona = new Persona(nombrePersona);		
			else
				persona = this.personas.get(nombrePersona);
			
			for(int i=0; i<nombresPreferencias.length;i++){
				if(!this.preferenciasHombres.existePersonaConNombre(nombresPreferencias[i])){
					this.esCoherente=false;
					return;
				}
				Persona personaPreferida = this.preferenciasHombres.personaConNombre(nombresPreferencias[i]);
				persona.agregarPreferenciaSiguiente(personaPreferida);
				
			}
			this.preferenciasMujeres.agregarPersona(persona);
			if(lectorArchivo.ready())
				linea=lectorArchivo.readLine();
			
		}
		
	}

	

	private void comprobarCoherencia() {
		
		if(!this.esCoherente)
			return;
		// Un problema coherente debe tener igual cantidad de hombres que mujeres
		if(this.preferenciasHombres.getCantidad()!=this.preferenciasMujeres.getCantidad())
			this.esCoherente=false;
		
		if(!esCoherentePar(this.preferenciasHombres,this.preferenciasMujeres) || !esCoherentePar(this.preferenciasHombres,this.preferenciasMujeres))
			this.esCoherente=false;			
	}

	private boolean esCoherentePar(TablaDePreferencias tabla1,
			TablaDePreferencias tabla2) {
		Iterator<Persona> iteradorPersonas=tabla1.getPersonas();
		while(iteradorPersonas.hasNext()){
			Persona p= iteradorPersonas.next();
			Iterator<Persona> iteradorPreferidos = p.obtenerIteradorPreferidos();
			while(iteradorPreferidos.hasNext()){
				if(!tabla2.existePersonaConNombre(iteradorPreferidos.next().darNombre()))
					return false;
			}
					
		}
		return true;
	}

	/*
	 * parsea una parte del archivo hasta encontrar una linea en blanco
	 */
	private void parsearPrimerParte(BufferedReader lectorArchivo) throws IOException {
		String linea=null;
		if(lectorArchivo.ready())
			linea=lectorArchivo.readLine();
		while(!linea.isEmpty() && lectorArchivo.ready()){
			if(!linea.contains(SEPARADOR_PRINCIPAL))
				throw new ErrorDeSintaxis("Se esperaba " + SEPARADOR_PRINCIPAL + " en esta linea");
			// separo la primer parte desde el separador principal, que es el nombre de la persona de sus preferencias
			String nombrePersona= linea.split(SEPARADOR_PRINCIPAL)[0],
					preferencias=linea.split(SEPARADOR_PRINCIPAL)[1];
			String[] nombresPreferencias = preferencias.split(SEPARADOR_NOMBRES);
		
			
			Persona persona = new Persona(nombrePersona);
			this.personas.put(nombrePersona, persona);
			
			for(int i=0; i<nombresPreferencias.length;i++){
				Persona personaPreferida;
				if(!personas.containsKey(nombresPreferencias[i])){
					personaPreferida = new Persona(nombresPreferencias[i]);
					this.personas.put(nombresPreferencias[i], personaPreferida);
				}
				else
					personaPreferida= personas.get(nombresPreferencias[i]);
				persona.agregarPreferenciaSiguiente(personaPreferida);
				
			}
			this.preferenciasHombres.agregarPersona(persona);
			if(lectorArchivo.ready())
				linea=lectorArchivo.readLine();
			
		}
	}
}
